package com.hanbang.gycatering.myviews;

import com.hanbang.gangyu.R;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class ColoredRatingBar extends View {

	Bitmap drawables;
	Bitmap progressBackground;
	private float starImageSize;
	Context mContext;
	private int mNumStars = 5;
	private float mRating = 0;
	private boolean mIndicator;
	private float slidePosition;

	public interface OnRatingBarChangeListener {

		void onRatingChanged(ColoredRatingBar ratingBar, float rating,
				boolean fromUser);

	}

	private OnRatingBarChangeListener mOnRatingBarChangeListener;

	public ColoredRatingBar(Context context) {
		this(context, null);
	}

	public ColoredRatingBar(Context context, AttributeSet attrs) {
		this(context, attrs, R.attr.coloredRatingBarStyle);
	}

	public ColoredRatingBar(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);

		TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.ColoredRatingBar, defStyle, 0);
		final boolean indicator = a.getBoolean(
				R.styleable.ColoredRatingBar_indicator, false);
		final float rating = a
				.getFloat(R.styleable.ColoredRatingBar_rating, -1);
		Drawable drawablesId = a
				.getDrawable(R.styleable.ColoredRatingBar_starFill);
		Drawable progressBackgroundId = a
				.getDrawable(R.styleable.ColoredRatingBar_starEmpty);
		starImageSize = a.getDimension(
				R.styleable.ColoredRatingBar_starImageSize, 20);
		a.recycle();
		drawables = drawableToBitmap(drawablesId);
		progressBackground = drawableToBitmap(progressBackgroundId);
		setIndicator(indicator);
		setRating(rating);
		init(context);
	}

	public static Bitmap drawableToBitmap(Drawable drawable) {
		// 取 drawable 的长宽
		int w = drawable.getIntrinsicWidth();
		int h = drawable.getIntrinsicHeight();

		// 取 drawable 的颜色格式
		Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
				: Bitmap.Config.RGB_565;
		// 建立对应 bitmap
		Bitmap bitmap = Bitmap.createBitmap(w, h, config);
		// 建立对应 bitmap 的画布
		Canvas canvas = new Canvas(bitmap);
		drawable.setBounds(0, 0, w, h);
		// 把 drawable 内容画到画布中
		drawable.draw(canvas);
		return bitmap;
	}

	private void init(Context context) {
		mContext = context;
		drawables = zoomImage(drawables, starImageSize, starImageSize);
		progressBackground = zoomImage(progressBackground, starImageSize,
				starImageSize);
	}

	public Bitmap zoomImage(Bitmap bgimage, double newWidth, double newHeight) {
		// 获取这个图片的宽和高
		float width = bgimage.getWidth();
		float height = bgimage.getHeight();
		// 创建操作图片用的matrix对象
		Matrix matrix = new Matrix();
		// 计算宽高缩放率
		float scaleWidth = ((float) newWidth) / width;
		float scaleHeight = ((float) newHeight) / height;
		// 缩放图片动作
		matrix.postScale(scaleWidth, scaleHeight);
		Bitmap bitmap = Bitmap.createBitmap(bgimage, 0, 0, (int) width,
				(int) height, matrix, true);
		return bitmap;
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		// draw empty stars bg
		for (int i = 0; i < mNumStars; i++) {
			drawStar(canvas, i);
		}

	}

	private void drawStar(Canvas canvas, int position) {
		float fraction = mRating - (position);
		Bitmap ratedStar = getRatedStar();
		if ((position + 1) < mRating) {
			canvas.drawBitmap(ratedStar, (position * ratedStar.getWidth()), 0,
					null);
		} else {
			if (fraction > 0 && fraction <= 1) {
				int sourceWidth = ratedStar.getWidth();
				int sourceHeight = ratedStar.getHeight();

				int targetWidth = (int) (ratedStar.getWidth() * fraction);
				int bgWidth = sourceWidth - targetWidth;

				if (targetWidth > 0) {
					Bitmap croppedBmp = Bitmap.createBitmap(ratedStar, 0, 0,
							targetWidth, sourceHeight);
					canvas.drawBitmap(croppedBmp, (position * sourceWidth), 0,
							null);
					// croppedBmp.recycle();
				}
				if (bgWidth > 0) {
					Bitmap croppedBg = Bitmap.createBitmap(progressBackground,
							targetWidth, 0, bgWidth, sourceHeight);
					canvas.drawBitmap(croppedBg, (position * sourceWidth)
							+ targetWidth, 0, null);
					// croppedBg.recycle();
				}
			} else {
				canvas.drawBitmap(progressBackground,
						(position * progressBackground.getWidth()), 0, null);
			}
		}

	}

	private Bitmap getRatedStar() {
		return drawables;
	}

	public int getNumStars() {
		return mNumStars;
	}

	public void setNumStars(int numStars) {
		this.mNumStars = numStars;
	}

	public float getRating() {
		return mRating;
	}

	public void setRating(float rating) {
		setRating(rating, false);
	}

	void setRating(float rating, boolean fromUser) {
		if (rating > mNumStars) {
			this.mRating = mNumStars;
		}
		this.mRating = rating;
		invalidate();
		dispatchRatingChange(fromUser);
	}

	public boolean isIndicator() {
		return mIndicator;
	}

	public void setIndicator(boolean indicator) {
		this.mIndicator = indicator;
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		if (progressBackground != null) {

			final int width = progressBackground.getWidth() * mNumStars;
			final int height = progressBackground.getHeight();
			setMeasuredDimension(width, height);
		}
	}

	@SuppressLint("ClickableViewAccessibility") @Override
	public boolean onTouchEvent(MotionEvent event) {
		if (!mIndicator) {
			return false;
		}

		int action = event.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			break;
		case MotionEvent.ACTION_MOVE:
		case MotionEvent.ACTION_UP:
			slidePosition = getRelativePosition(event.getX());
			int newRating = (int) slidePosition + 1;
			if (newRating != mRating) {
				setRating(newRating, true);
			}
			break;
		case MotionEvent.ACTION_CANCEL:
			break;
		default:
			break;
		}

		return true;
	}

	private float getRelativePosition(float x) {
		float position = x / progressBackground.getWidth();
		position = Math.max(position, 0);
		return Math.min(position, mNumStars - 1);
	}

	/**
	 * Sets the listener to be called when the rating changes.
	 * 
	 * @param listener
	 *            The listener.
	 */
	public void setOnRatingBarChangeListener(OnRatingBarChangeListener listener) {
		mOnRatingBarChangeListener = listener;
	}

	/**
	 * @return The listener (may be null) that is listening for rating change
	 *         events.
	 */
	public OnRatingBarChangeListener getOnRatingBarChangeListener() {
		return mOnRatingBarChangeListener;
	}

	void dispatchRatingChange(boolean fromUser) {
		if (mOnRatingBarChangeListener != null) {
			mOnRatingBarChangeListener.onRatingChanged(this, getRating(),
					fromUser);
		}
	}
}
